/*
 * ContextPropertyDefinition.java
 *
 * Created on 20 de diciembre de 2004, 13:00
 */

package ocp.context;

import java.util.Vector;
import java.util.Enumeration;

/**
 * <p>This class defines a property definition, that's it, the definition of an ontological property, 
 * composed of:
 *
 * <ul>
 * <li>name
 * <li>domain(s)
 * <li>range(s)
 * <li>properties
 * </ul>
 * 
 * <p>The property is in the form:<br>
 * name(domains) -> ranges.
 * <p>example:<br>
 * hasChild(Person, Person) -> Person<br>
 * transitive = false, symmetric = false, functional = false, hasInverse = true (hasParent).
 *
 * @author Ignacio Nieto Carvajal
 */
public class ContextPropertyDefinition implements java.io.Serializable  {
    
    /** the name of this property definition */
    protected String name;
    
    /** is the property transitive? */
    protected boolean transitive = false;
    
    /** is the property symmetric? */
    protected boolean symmetric = false;
    
    /** is the preperty functional? */
    protected boolean functional = false;
    
    /** has the property an inverse function? */
    protected boolean hasInverse = false;
    
    /** the inverse property (if any) of this property */
    protected ContextPropertyDefinition inverse = null;
    
    /** the vector with the ranges of the property in order */
    protected Vector<ContextPropertySpace> ranges = new Vector<ContextPropertySpace>();
    
    /** the vector with the domains of the property in order */
    protected Vector<ContextPropertySpace> domains = new Vector<ContextPropertySpace>();
    
    /** vector of equivalent properties */
    protected Vector equivalentProperties = new Vector();
    
    /** Creates a new instance of ContextPropertyDefinition */
    public ContextPropertyDefinition(String name) {
        this.name = name;
    }
    
    /** Creates a new instance of ContextPropertyDefinition */
    public ContextPropertyDefinition(String name, ContextPropertyDefinition inverse) {
        this(name);
        this.inverse = inverse;
        this.hasInverse = true;
    }
    
    public String getName()                         { return name; }
    
    public ContextPropertyDefinition setTransitive(boolean transitive)   { this.transitive = transitive;  return this;}
    public ContextPropertyDefinition setSymmetric(boolean symmetric)     { this.symmetric = symmetric;  return this;}
    public ContextPropertyDefinition setFunctional(boolean functional)   { this.functional = functional;  return this;}
    public ContextPropertyDefinition setInverse(ContextPropertyDefinition cpd)   {
        inverse = cpd;
        if (cpd != null) hasInverse = true;
        else hasInverse = false;
        return this;            
    }
    public boolean isTransitive()                   { return transitive; }
    public boolean isSymmetric()                    { return symmetric; }
    public boolean isFunctional()                   { return functional; } 
    public boolean hasInverse()                     { return hasInverse; }
    public ContextPropertyDefinition getInverse()   { return inverse; }
    public void removeInverse()         {
        inverse = null;
        hasInverse = false;
    }
    
    public ContextPropertyDefinition addDomain(ContextPropertySpace domain)      { domains.addElement(domain); return this;}
    public ContextPropertyDefinition removeDomain(ContextPropertySpace domain)   { domains.removeElement(domain);  return this;}
    public ContextPropertyDefinition addRange(ContextPropertySpace range)        { ranges.addElement(range);  return this;}
    public ContextPropertyDefinition removeRange(ContextPropertySpace range)     { ranges.removeElement(range);  return this;}
    public ContextPropertyDefinition removeAllDomains()  { domains.removeAllElements();  return this;}
    public ContextPropertyDefinition removeAllRanges()   { domains.removeAllElements();  return this;}
    public Enumeration<ContextPropertySpace> getDomains() { return domains.elements(); }
    public Enumeration<ContextPropertySpace> getRanges()  { return ranges.elements(); }
    public int getNumberOfDomains() { return domains.size(); }
    public int getNumberOfRanges()  { return ranges.size(); }
    public ContextPropertySpace getDomain(int i)    { return (ContextPropertySpace) domains.elementAt(i); }
    public ContextPropertySpace getRange(int i)     { return (ContextPropertySpace) ranges.elementAt(i); }
    
    public ContextPropertyDefinition isEquivalentTo(ContextPropertyDefinition cpd) {
        if (!equivalentProperties.contains(cpd))
            equivalentProperties.addElement(cpd);
         return this;
    }
    public ContextPropertyDefinition isNotEquivalentTo(ContextPropertyDefinition cpd) {
        equivalentProperties.removeElement(cpd);
         return this;
    }
    
    public boolean validate(ContextProperty prop) {
        // TODO
        return true;
    }
    public String toString() {
        String temp = "" + name + "(";
        for (Enumeration e1 = domains.elements(); e1.hasMoreElements();)
            temp += e1.nextElement().toString();
        temp += ") -->";
        for (Enumeration e2 = ranges.elements(); e2.hasMoreElements();)
            temp += e2.nextElement().toString();
        temp +=". transitive="+transitive+",symmetric="+symmetric+",functional="+functional+",hasInverse="+hasInverse;
        
        return temp;
    }
    
    public String toXML() {
        String xml = "<ContextPropertyDefinition name=\""+name+"\" transitive=\""+transitive+"\" "+
            "symmetric=\""+symmetric+"\" functional=\""+functional+"\">\n";
        if (hasInverse)
            xml+= "\t<Inverse>"+inverse.getName()+"</Inverse>\n";
        xml += "\t<Domains>";
        Enumeration<ContextPropertySpace> doms = domains.elements();
        while (doms.hasMoreElements()) {
            ContextPropertySpace dom = doms.nextElement();
            xml  += "\t\t<Domain>"+dom.toXML()+"</Domain>\n";
        }
        xml += "\t</Domains>";
        xml += "\t<Ranges>";
        Enumeration<ContextPropertySpace> rans = ranges.elements();
        while (rans.hasMoreElements()) {
            ContextPropertySpace ran = rans.nextElement();
            xml  += "\t\t<Range>"+ran.toXML()+"</Range>\n";
        }
        xml += "\t</Ranges>";
        xml += "</ContextPropertyDefinition>\n";

        return xml;
    }
    
    public boolean equals (Object o) {
        if (o instanceof ContextPropertyDefinition) {
            ContextPropertyDefinition cpd = (ContextPropertyDefinition ) o;
            return cpd.toString().equals(this.toString());
        }
        return false;
    }
}
